package cn.aitrox.ry.app.web.service.impl;

import cn.aitrox.ry.app.web.service.ImageTransferService;
import cn.aitrox.ry.app.web.vo.image.transfer.ImageTransferResultQueryOutVo;
import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.enumtype.ProcessStatusEnum;
import cn.aitrox.ry.service.anno.dto.task.TaskDetailDto;
import cn.aitrox.ry.service.anno.dto.task.in.AnnoSeriesDto;
import cn.aitrox.ry.service.anno.feign.TaskFeign;
import cn.aitrox.ry.service.config.enumtype.ImageLayoutEnum;
import cn.aitrox.ry.service.config.enumtype.ImageTransferModeEnum;
import cn.aitrox.ry.service.image.dto.image.transfer.in.ImageTransferExecuteInDto;
import cn.aitrox.ry.service.image.dto.image.transfer.in.ImageTransferPauseInDto;
import cn.aitrox.ry.service.image.dto.image.transfer.in.ImageTransferRestartInDto;
import cn.aitrox.ry.service.image.dto.image.transfer.in.ImageTransferResultExportInDto;
import cn.aitrox.ry.service.image.dto.image.transfer.out.ImageTransferResultExportDataDto;
import cn.aitrox.ry.service.image.enumtype.TransferItemRelationTypeEnum;
import cn.aitrox.ry.service.image.feign.ImageTransferFeign;
import cn.aitrox.ry.util.ArrayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ImageTransferServiceImpl implements ImageTransferService {

    public static Map<ImageLayoutEnum, ImageTransferModeEnum> layoutModeMap = new HashMap<>();

    static {
        layoutModeMap.put(ImageLayoutEnum.VIDEO_ANNO, ImageTransferModeEnum.VIDEO_FRAME_EXTRACT);
    }

    @Autowired
    @Lazy
    private ImageTransferFeign imageTransferFeign;

    @Autowired
    @Lazy
    private TaskFeign taskFeign;

    @Override
    public RespResult<ImageTransferResultQueryOutVo> resultQuery(Integer taskId) {

        TaskDetailDto taskDetail = taskFeign.read(taskId);

        ImageTransferModeEnum transferModeEnum = getTransferModeEnum(taskDetail.getImageLayout());
        if (null == transferModeEnum) {
            ImageTransferResultQueryOutVo outVo = new ImageTransferResultQueryOutVo(null, null, 0, 0, 0, 0, 0, 0, 0);
            return RespResult.ok(outVo);
        }

        if (ArrayUtil.isEmpty(taskDetail.getSeriesList())) {
            ImageTransferResultQueryOutVo outVo = new ImageTransferResultQueryOutVo(transferModeEnum.getMode(), ProcessStatusEnum.NOT_START.getStatus(), 0, 0, 0, 0, 0, 0, 0);
            return RespResult.ok(outVo);
        }

        List<String> seriesUidInTask = taskDetail.getSeriesList().stream().map(AnnoSeriesDto::getSeriesUid).distinct().collect(Collectors.toList());

        List<ImageTransferResultExportDataDto> data = imageTransferFeign.resultExport(new ImageTransferResultExportInDto(taskId.toString(), TransferItemRelationTypeEnum.ANNO_TASK_ID.getRelationType(), transferModeEnum.getMode(), seriesUidInTask));
        if (ArrayUtil.isEmpty(data)) {
            ImageTransferResultQueryOutVo outVo = new ImageTransferResultQueryOutVo(transferModeEnum.getMode(), ProcessStatusEnum.NOT_START.getStatus(), taskDetail.getSeriesList().size(), 0, 0, 0, 0, 0, taskDetail.getSeriesList().size());
            return RespResult.ok(outVo);
        }

        List<String> prcessedSeriesList = data.stream().map(ImageTransferResultExportDataDto::getSeriesUid).distinct().collect(Collectors.toList());
        int addCount = ((Long) (taskDetail.getSeriesList().stream().filter(x -> !prcessedSeriesList.contains(x.getSeriesUid())).count())).intValue();

        List<ImageTransferResultExportDataDto> processedDataList = data.stream().filter(x -> seriesUidInTask.contains(x.getSeriesUid())).collect(Collectors.toList());

        int totalCount = taskDetail.getSeriesList().size();

        int failCount = 0;

        int successCount = 0;

        int processCount = 0;

        int notStartCount = 0;

        int pauseCount = 0;

        for (ImageTransferResultExportDataDto item : processedDataList) {
            prcessedSeriesList.add(item.getSeriesUid());
            ProcessStatusEnum statusEnum = ProcessStatusEnum.getEnum(item.getStatus());
            switch (statusEnum) {
                case SUCCESS:
                    successCount++;
                    break;
                case FAIL:
                    failCount++;
                    break;
                case NOT_START:
                    notStartCount++;
                    break;
                case PROCESSING:
                    processCount++;
                    break;
                case PAUSE:
                    pauseCount++;
                    break;
                default:
                    break;
            }
        }
        ProcessStatusEnum processStatusEnum;
        if (failCount > 0) {
            processStatusEnum = ProcessStatusEnum.FAIL;
        } else if (addCount == 0 && successCount == totalCount) {
            processStatusEnum = ProcessStatusEnum.SUCCESS;
        } else if (pauseCount > 0) {
            processStatusEnum = ProcessStatusEnum.PAUSE;
        } else if (notStartCount > 0 || processCount > 0) {
            processStatusEnum = ProcessStatusEnum.PROCESSING;
        } else {
            processStatusEnum = ProcessStatusEnum.NOT_START;
        }

        ImageTransferResultQueryOutVo outVo = new ImageTransferResultQueryOutVo(transferModeEnum.getMode(),
                processStatusEnum.getStatus(),
                totalCount,
                successCount,
                failCount,
                processCount,
                notStartCount,
                pauseCount,
                addCount);
        return RespResult.ok(outVo);
    }

    @Override
    public RespResult execute(Integer taskId) {
        TaskDetailDto taskDetail = taskFeign.read(taskId);

        ImageTransferModeEnum transferModeEnum = getTransferModeEnum(taskDetail.getImageLayout());

        if (null == transferModeEnum) {
            return RespResult.ok();
        }

        List<AnnoSeriesDto> seriesList = taskDetail.getSeriesList();
        if (ArrayUtil.isEmpty(seriesList)) {
            return RespResult.ok();
        }

        // 任务导入的序列
        List<String> seriesUidList = seriesList.stream().map(AnnoSeriesDto::getSeriesUid).distinct().collect(Collectors.toList());
        if (ArrayUtil.isEmpty(seriesUidList)) {
            return RespResult.ok();
        }

        // 查询已执行过的序列
        List<ImageTransferResultExportDataDto> exportDataDtos = imageTransferFeign.resultExport(new ImageTransferResultExportInDto(taskId.toString(), TransferItemRelationTypeEnum.ANNO_TASK_ID.getRelationType(), transferModeEnum.getMode(), seriesUidList));

        // 算出需要进行处理的序列
        List<String> needExecuteSeriesList = new ArrayList<>();
        if (ArrayUtil.isEmpty(exportDataDtos)) {
            needExecuteSeriesList = seriesUidList;
        } else {
            List<String> executedSeriesList = exportDataDtos.stream().map(ImageTransferResultExportDataDto::getSeriesUid).distinct().collect(Collectors.toList());
            List<String> addSeriesList = seriesUidList.stream().filter(x -> !executedSeriesList.contains(x)).collect(Collectors.toList());
            List<String> pauseSeriesList = exportDataDtos.stream().filter(x -> ProcessStatusEnum._isPause(x.getStatus())).map(ImageTransferResultExportDataDto::getSeriesUid).distinct().collect(Collectors.toList());
            needExecuteSeriesList.addAll(addSeriesList);
            needExecuteSeriesList.addAll(pauseSeriesList);

        }
        if (ArrayUtil.isEmpty(needExecuteSeriesList)) {
            return RespResult.ok();
        }

        // 去重
        needExecuteSeriesList = needExecuteSeriesList.stream().distinct().collect(Collectors.toList());

        ImageTransferExecuteInDto inDto = new ImageTransferExecuteInDto(taskId.toString(), TransferItemRelationTypeEnum.ANNO_TASK_ID.getRelationType(), needExecuteSeriesList, transferModeEnum.getMode());
        return imageTransferFeign.execute(inDto);
    }

    @Override
    public List<ImageTransferResultExportDataDto> resultExportData(Integer taskId) {
        TaskDetailDto taskDetail = taskFeign.read(taskId);
        ImageTransferModeEnum transferModeEnum = getTransferModeEnum(taskDetail.getImageLayout());
        if (null == transferModeEnum) {
            return new ArrayList<>();
        }
        if (ArrayUtil.isEmpty(taskDetail.getSeriesList())) {
            return new ArrayList<>();
        }
        List<String> seriesUidInTask = taskDetail.getSeriesList().stream().map(AnnoSeriesDto::getSeriesUid).distinct().collect(Collectors.toList());

        return imageTransferFeign.resultExport(new ImageTransferResultExportInDto(taskId.toString(), TransferItemRelationTypeEnum.ANNO_TASK_ID.getRelationType(), transferModeEnum.getMode(), seriesUidInTask));
    }

    @Override
    public RespResult restart(Integer taskId) {
        TaskDetailDto taskDetail = taskFeign.read(taskId);

        ImageTransferModeEnum transferModeEnum = getTransferModeEnum(taskDetail.getImageLayout());

        if (null == transferModeEnum) {
            return RespResult.ok();
        }
        return imageTransferFeign.restart(new ImageTransferRestartInDto(taskId.toString(), TransferItemRelationTypeEnum.ANNO_TASK_ID.getRelationType(), transferModeEnum.getMode()));
    }

    @Override
    public RespResult pause(Integer taskId) {
        TaskDetailDto taskDetail = taskFeign.read(taskId);

        ImageTransferModeEnum transferModeEnum = getTransferModeEnum(taskDetail.getImageLayout());

        if (null == transferModeEnum) {
            return RespResult.ok();
        }
        return imageTransferFeign.pause(new ImageTransferPauseInDto(taskId.toString(), TransferItemRelationTypeEnum.ANNO_TASK_ID.getRelationType(), transferModeEnum.getMode()));
    }

    public ImageTransferModeEnum getTransferModeEnum(String imageLayout) {
        ImageLayoutEnum imageLayoutEnum = ImageLayoutEnum.getEnumByValue(imageLayout);
        ImageTransferModeEnum imageTransferModeEnum = layoutModeMap.get(imageLayoutEnum);
        return imageTransferModeEnum;
    }
}
